#include "HTTPHandlerTask.h"
#include "StringUtil.h"
#include "File.h"
#include "HTTPServer.h"
SK

HTTPHandlerTask::HTTPHandlerTask (HTTPServer *server, Thread *t, Socket *con, const String& siteRoot)
:server (server), con (con), root (siteRoot), thread (t)
{
    con->setTimeout (5000);
}

HTTPHandlerTask::~HTTPHandlerTask ()
{
    delete con;
}


void HTTPHandlerTask::parseMimeType (const String& url)
{
    int extLoc = url.find ('.');

    if (extLoc == String::npos)
        requestInfo->mimeType = "text/html";
    else
    {
        String ext = url.substr (extLoc +1);

        if (ext == "htm" || ext == "html")
            requestInfo->mimeType = "text/html";
        else if (ext == "xml")
            requestInfo->mimeType = "text/xml";
        else if (ext == "jpg" || ext == "jpeg")
            requestInfo->mimeType = "image/jpeg";
        else if (ext == "png")
            requestInfo->mimeType = "image/png";
        else if (ext == "css")
            requestInfo->mimeType = "text/css";
        else if (ext == "js")
            requestInfo->mimeType = "text/javascript";
        else
            requestInfo->mimeType = "text/html";
    }
}

void HTTPHandlerTask::parseRequest (const String& request)
{  
    StringArray lines = StringUtil::split (request, '\n');
    StringArray::iterator it;
    int curLine = 0;

    for (it = lines.begin(); it != lines.end(); it++)
    {
        if (curLine == 0)
        {
            //GET / HTTP/1.1
            StringArray req = StringUtil::split ((*it), ' ');
            requestInfo->method = req[0];
            requestInfo->url = req [1];
            parseMimeType (req [1]);
        }   
        else
        {
            int colLoc = (*it).find (":");
            if (colLoc == String::npos)
                continue;   //malformatted header line

            String key = StringUtil::toLowerCase ((*it).substr (0, colLoc));
            String val = StringUtil::toLowerCase ((*it).substr (colLoc+2));

            requestInfo->headers.insert (KeyValuePair::value_type (key, val));

            if (key == "connection" && val == "keep-alive")     
                requestInfo->keepAlive = true;
        }
        curLine++;
    }
}

bool HTTPHandlerTask::processRequest (void)
{
    if (requestInfo->url.find ("~") != String::npos)
        return false;

    if (requestInfo->url.find ("..") != String::npos)
        return false;   //which error code? malicious request

    File fle;

    if (!fle.open (root + requestInfo->url, "rb"))
        return false;   //error 404

        
    byte buf [4097];
    int curPos = 0;
    int fileSize = fle.getSize();

    response = "HTTP/1.1 200 OK\r\n";
    response += "host: " + requestInfo->headers.find ("host")->second + "\r\n";
    response += "Content-Type: " + requestInfo->mimeType + "\r\n";  //need to finish this
	response += "Content-Length: " + StringUtil::toString (fileSize) + "\r\n\r\n";

    con->sendAll((byte *)response.c_str(), response.length());

    while (curPos < fileSize)
    {
        int read = fle.read (buf, 4096);
        con->sendAll (buf, read);
        curPos += read;
    }

    fle.close();
    return true;
}

void HTTPHandlerTask::sendResponse (void)
{
    con->sendAll ((byte *)response.c_str(), response.length());
    response = "";
}

void HTTPHandlerTask::run (void)
{
    byte buffer [4097];
    String request;
    int rec=1;

    bool keepAlive;
    while (rec > 0)
    {
        keepAlive = false;
        rec = con->recv (buffer, 4096);
        if (rec < 1)
        {
            con->close();
            server->_onRequestComplete (thread);
            return;
        }

        buffer [rec] = 0;
        request += (char *)buffer;

        if (request.find ("\r\n\r\n") != String.npos)
        {
            int endPos=1;
            
            while (endPos != String.npos)
            {
                endPos = request.find ("\r\n\r\n");

                if (endPos == String.npos)
                    break;

                String req = request.substr (0, endPos);

                //request complete, parse it
                
                requestInfo = new RequestInfo ();
                parseRequest (req);
                processRequest ();
                sendResponse ();
                keepAlive = requestInfo->keepAlive;
                delete requestInfo;
                request = request.substr (endPos + 4);
            }
        }

        if (!keepAlive)
        {
            con->close();
        }
    }

    server->_onRequestComplete (thread);
}

EK